#include <cstdio>
#include <iostream>
#include <sstream>
#include "../Headers/log.h"
#include "../Headers/types.h"
#include "ns.rpc.h"
#include "nameserver.h"

// Constructor
TOB::Nameserver::Nameserver(std::string host) {
	clnt = clnt_create(host.c_str(), NS_PROG, NS_VERSION, "udp");
	if(clnt == NULL) {
		Log::error("Cannot connect to nameserver");
		connected = false;
	} 
  else {
	  Log::event("Connected to nameserver");
	  connected = true;
	 }
}


// Destructor
TOB::Nameserver::~Nameserver() {
  if (clnt != NULL && connected) {
	  clnt_destroy(clnt);
  }
}	


// Encapsulate connected
bool TOB::Nameserver::isConnected() {
  return connected;
}


// Request address
Code::Type TOB::Nameserver::requestAddress(Server::Type server, TOB::Nameserver::IP &ipAddr) {
	if(!connected) { return Code::NS_DoesntRespond; }

	int32 srv = static_cast<int32>(server);
	nsResult *result = requestaddr_1(&srv, clnt);

	if(!result) {
		Log::error("Failed to receive data from nameserver");
		return Code::NS_DoesntRespond;
	}

	if(!result->result) {
		Log::error("Server not found on nameserver");
		return Code::NS_ServerNotFound;
	}
	
	ipAddr = result->ipAddr;
	return Code::Okay;
}


// Convert ip -> string
Code::Type TOB::Nameserver::convertIP(TOB::Nameserver::IP ipAddr, std::string &output) {
	std::stringstream stream;
	uint8 *addr = reinterpret_cast<uint8*>(&ipAddr);

	for(uint32 i = 0; i < IPLENGTH; ++i) {
		if(i) { stream << '.'; }
		stream << (int) addr[i];
	}

	output = stream.str();
	return Code::Okay;
}


// Convert string -> ip
Code::Type TOB::Nameserver::convertString(std::string &input, TOB::Nameserver::IP &ipAddr) {
	uint32 addr32[IPLENGTH];
	uint8 *addr = reinterpret_cast<uint8*>(&ipAddr);
	if(sscanf(input.c_str(), "%u.%u.%u.%u", 
			&addr32[0], &addr32[1], &addr32[2], &addr32[3]) == 4) {
			for(uint32 i = 0; i < IPLENGTH; ++i) {
        addr[i] = static_cast<uint8>(addr32[i]);
			}
	} else {
		return Code::NS_CantConvert;
	}
  return Code::Okay;
}
